package com.ruben.aop;

import com.ruben.annotation.Validator;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName: ValidatorAop
 * @Description:
 * @Date: 2020/8/17 20:50
 * *
 * @author: achao<achao1441470436 @ gmail.com>
 * @version: 1.0
 * @since: JDK 1.8
 */
@Aspect
@Component
public class ValidatorAop {
    /**
     * 参数校验AOP
     *
     * @param joinPoint 织入点为这个注解
     * @param validator 自定义的注解
     * @return
     */
    @Around("@annotation(validator)")
    public Object validateParam(ProceedingJoinPoint joinPoint, Validator validator) {
        //获取错误参数(也就是我们注解里面的bindingResult)
        String value = validator.value();
        //获取所有参数名
        String[] parameterNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
        BindingResult bindingResult = null;
        //遍历所有参数名，如果参数名相同，则根据当前i作为下标去获取参数
        for (int i = 0; i < parameterNames.length; i++) {
            if (value.equals(parameterNames[i])) {
                bindingResult = (BindingResult) joinPoint.getArgs()[i];
            }
        }
        //返回一个map
        Map<String, Object> map = new HashMap<>(1 << 2);
        //如果bindingResult不为空并且bindingResult数组不为空(hasErrors是调用List的isEmpty取反)
        if (bindingResult != null && bindingResult.hasErrors()) {
            map.put("success", false);
            map.put("code", HttpStatus.BAD_REQUEST);
            //拼接结果(个人喜欢把所有错误信息返回，也可以只返回第一个提升效率)
            map.put("msg", bindingResult.getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(" ")));
            return map;
        }
        try {
            //方法执行
            return joinPoint.proceed();
        } catch (Throwable throwable) {
            //方法执行必须抛出一个Throwable异常
            throwable.printStackTrace();
        }
        return null;
    }
}
